package cn.le.studyEnum;

import cn.le.io.OSExecute;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.TreeSet;

/**
 * enum可以将一组具名的值的有限集合创建为一种新的类型，而这些具名的值可以作为
 * 常规的程序组件使用。
 *
 * 编译器不允许我们将一个enum实例当作class类型，因为没有enum元素都是一个LikeClasses类型的
 * static final实例，由于它们是static实例，无法访问外部类的非static元素或方法，所有对于内部
 * 的enum的实例而言，其行为与一般的内部类并不相同。
 *
 */
public class EnumClass {

    public static void main(String[] args) {

        for (Shrubbery s : Shrubbery.values()) {
            //ordinal()返回一个int值，这是每个enum实例在声明时的顺序
            System.out.println(s + "ordinal:" + s.ordinal());
            //比较此枚举与指定对象的顺序。
            System.out.println(s.compareTo(Shrubbery.CRAWLING));
            System.out.println(s.equals(Shrubbery.CRAWLING));
            System.out.println(s == Shrubbery.CRAWLING);
            // 返回与此枚举常量的枚举类型相对应的 Class 对象
            System.out.println(s.getDeclaringClass());
            System.out.println(s.name());

            for (String str : "GROOUND CRAWLING HANGING".split(" ")) {
                //返回带指定名称的指定枚举类型的枚举常量,如果不存在给定名字的实例，将会抛出异常
                Shrubbery shrub = Enum.valueOf(Shrubbery.class, str);
                System.out.println(shrub);

            }
        }
    }
}

/**
 * 创建enum时，编译器会为你生成一个相关的类，这个类继承子java.lang.Enum
 */
enum Shrubbery {

    GROOUND,
    CRAWLING,
    HANGING
}

/**
 * 利用反射探究values()方法
 * <p>
 * values()是由編輯器添加的static方法，在创建Explore的过程中，编辑器还为其提供了valueOf()方法，
 * Enum类中已经有了一个valueOf()方法，不过需要2个参数，而编辑器新增加的这个方法只需要一个，
 */

class Reflecton {

    public static Set<String> analyze(Class<?> enumClass) {
        System.out.println("----------Analyzing " + enumClass + "------");
        System.out.println("interfaces");
        //返回表示某些接口的 Type，这些接口由此对象所表示的类或接口直接实现。
        for (Type t : enumClass.getGenericInterfaces()) {
            System.out.println(t);
        }
        System.out.println("Base:" + enumClass.getSuperclass());
        System.out.println("Methods");
        Set<String> methods = new TreeSet<String>();

        /**
         * 方法名+方法行参=方法签名（确定方法的唯一性，方法的id）
         */
        for (Method m : enumClass.getDeclaredMethods()) {

            //按照声明顺序返回 Class 对象的数组，这些对象描述了此 Method 对象所表示的方法的形参类型。
            Class<?>[] parameterTypes = m.getParameterTypes();
            String types = "";
            for (Class<?> clas : parameterTypes) {
                String parameterName = clas.getName();
                types += parameterName+",";
            }
            methods.add(m.getName()+"("+types+")");
        }
        System.out.println(methods);
        return methods;
    }

    public static void main(String[] args) {

        Set<String> explreMethods = analyze(Exlpre.class);
        Set<String> enumMethods = analyze(Enum.class);
        System.out.println("Explore removeAll(enum)?" + explreMethods.containsAll(enumMethods));
        explreMethods.removeAll(enumMethods);
        System.out.println(explreMethods);

        //javap java反编译命令
        //OSExecute.command("javap /home/le/JavaCode/Dailypractice/Javabasis/target/classes/cn/le/studyEnum/Exlpre");

        System.out.println("-----------------------------------------------------");
        /*
          由于values（）方法是由编译器插入到enum定义中的static方法，所以如果将enum实力向上转型为Enum，
          那么values()方法就不可用访问了，不过，在class中有个getEnumConstants()方法，
          所以即使Enum接口没有values()方法，仍然可以通告class对象获取所有enum实例
         */
        Enum e = Exlpre.THERE;
        for (Enum en : e.getClass().getEnumConstants())
        {
            System.out.println(en);
        }
        // getEnumConstants()方法是class上的方法，所以普通的，类也是可以调用的，不过将返回为null
        Class<Integer> inclass = Integer.class;
        for (Object en: inclass.getEnumConstants()) {
            System.out.println(en);
        }

        //用javap命令对Exlpre.class进行编译所得
        /*public static final cn.le.studyEnum.Exlpre HERE;
        public static final cn.le.studyEnum.Exlpre THERE;
        public static cn.le.studyEnum.Exlpre[] values();
        public static cn.le.studyEnum.Exlpre valueOf(java.lang.String);
        static {};*/

    }

}

enum Exlpre {
    HERE, THERE
}













